home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / SAT 2.4.0 / SAT / Add-ons / Sprite behavior / SATGridToolbox.p < prev    next >
Encoding:
Text File  |  1997-02-24  |  13.0 KB  |  373 lines  |  [TEXT/PJMM]

  1. {SATGridToolbox}
  2. {}
  3. {Routines for SAT-based games with a game world defined by a grid.}
  4. {Note that this is the "Oxyd"-style world, where movement isn't contrained to the grid,}
  5. {but obstacles etc are defined by it. It is NOT ment for strict grid movement, as in PacMan!}
  6. {}
  7. {Limitations and assumptions:}
  8. {• Your grid is defined in the unit SATGridStubs.}
  9. {• All free space grid values are smaller than the blocked ones. (Specified by kFreeSpace.) }
  10. {• Sprites should not be bigger (wider/higher) than the grid spaces. (Sprites only check with the}
  11. {corners of the hotRects, which mens that a small grid obstacle could pass right through it!)}
  12.  
  13. unit SATGridToolbox;
  14.  
  15. interface
  16.  
  17.     uses
  18. {$IFC UNDEFINED THINK_PASCAL}
  19.         Types, QuickDraw, Fonts, Events, Packages, Menus, Dialogs, Windows,{}
  20.         OSUtils, ToolUtils, {OSEvents,}
  21.         Resources, 
  22. {$ENDC}
  23.         SAT, SATToolbox, SATGridStubs;
  24.  
  25.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  26. {procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr); SKIT?}
  27.     function Pt2GridValue (p: Point): GridSpaceType;
  28.     procedure LoadGrid (resNum: Integer);
  29.     procedure DrawAllTiles;
  30.     function PtInGrid (p: Point): Boolean;
  31.     procedure GridTest (theSprite: FixSpritePtr);
  32.  
  33. implementation
  34.  
  35. {Load the grid from a TEXT resource.}
  36.     procedure LoadGrid (resNum: Integer);
  37.         type
  38.             CharArr = packed array[0..99999] of Char;
  39.             CharArrPtr = ^CharArr;
  40.             CharArrHnd = ^CharArrPtr;
  41.         var
  42.             hnd: CharArrHnd;
  43.             howMuch: Longint;
  44.             h, v: Integer;
  45.     begin
  46.         hnd := CharArrHnd(GetResource('TEXT', resNum));
  47.         if hnd = nil then
  48.             exit(LoadGrid);
  49.         if GetHandleSize(Handle(hnd)) > SizeOf(tileArray) then
  50.             howMuch := SizeOf(tileArray)
  51.         else
  52.             howMuch := GetHandleSize(Handle(hnd));
  53.  
  54.         HLock(Handle(hnd));
  55.  
  56.         h := 0;
  57.         v := 0;
  58.         howMuch := 0;
  59.  
  60.         while howMuch < GetHandleSize(Handle(hnd)) do
  61.             begin
  62.                 if hnd^^[howMuch] = Char(13) then
  63.                     begin
  64.                         h := 0;
  65.                         v := v + 1;
  66.                     end
  67.                 else
  68.                     begin
  69.                         if h < kArraySizeH then
  70.                             if v < kArraySizeV then
  71.                                 tileArray[h, v] := hnd^^[howMuch];
  72.                         h := h + 1;
  73.                     end;
  74.  
  75.                 howMuch := howMuch + 1;
  76.             end;
  77.  
  78.         HUnLock(Handle(hnd));
  79.  
  80. {BlockMove(Ptr(hnd^), @tileArray[0, 0], howMuch);}
  81.         ReleaseResource(Handle(hnd));
  82.     end; {LoadGrid}
  83.  
  84. {PtInGrid: is the point blocked or free?}
  85. {Needs improving: several different grid values should be free!}
  86.  
  87.     function PtInGrid (p: Point): Boolean;
  88.     begin
  89.         PtInGrid := tileArray[p.h div kTileSizeH][p.v div kTileSizeV] > kFreeSpace;
  90.     end; (*PtInGrid*)
  91.  
  92.  
  93. {Get the grid value in a point. A sprite can, for example, test with its center!}
  94.  
  95.     function Pt2GridValue (p: Point): GridSpaceType;
  96.     begin
  97.         Pt2GridValue := tileArray[p.h div kTileSizeH][p.v div kTileSizeV];
  98.     end; (*Pt2GridValue*)
  99.  
  100.     procedure GetGridRect (p: Point; var r: Rect);
  101.     begin
  102.         SetRect(r, p.h div kTileSizeH * kTileSizeH, p.v div kTileSizeV * kTileSizeV, (p.h div kTileSizeH + 1) * kTileSizeH, (p.v div kTileSizeV + 1) * kTileSizeV);
  103.     end; (*GetGridRect*)
  104.  
  105.     function RectSeparateRect (theSprite: SpritePtr; var anotherRect: Rect): Integer;
  106.         var
  107.             distance: array[0..3] of Integer;
  108.             shortest, shortestDistance, i: Integer;
  109.             bounds1, bounds2: Rect;
  110.     begin
  111.         bounds1 := theSprite^.hotRect;
  112.         OffsetRect(bounds1, theSprite^.position.h, theSprite^.position.v);
  113.  
  114.         bounds2 := anotherRect;
  115.  
  116. (*Calculate the distance to separate the sprites in every direction*)
  117.         distance[0] := bounds2.top - bounds1.bottom; {up}
  118.         distance[1] := bounds2.bottom - bounds1.top; {down}
  119.         distance[2] := bounds2.right - bounds1.left; {right}
  120.         distance[3] := bounds2.left - bounds1.right; {left}
  121.  
  122. (*Find the shortest distance*)
  123.         shortest := 0;
  124.         shortestDistance := abs(distance[0]);
  125.         for i := 1 to 3 do
  126.             if abs(distance[i]) < shortestDistance then
  127.                 begin
  128.                     shortest := i;
  129.                     shortestDistance := abs(distance[i]);
  130.                 end;
  131.  
  132. (*Move the sprite in the appropriate direction*)
  133.         case shortest of
  134.             0, 1: 
  135.                 theSprite^.position.v := theSprite^.position.v + distance[shortest];
  136.             2, 3: 
  137.                 theSprite^.position.h := theSprite^.position.h + distance[shortest];
  138.         end; {case}
  139.         RectSeparateRect := shortest;
  140.     end; (*RectSeparateRect*)
  141.  
  142.  
  143. {GridTest: A complex function that tests whether a sprite is in free space or not, and bounces}
  144. {off grid obstacles if not.}
  145.  
  146.     procedure GridTest (theSprite: FixSpritePtr);
  147.         var
  148.             p1, p2, p3, p4: Point;
  149.             bounds, gridRect: Rect;
  150.             sum: Integer;
  151.             case1, case2: Point;
  152.             diff1, diff2: Integer;
  153.     begin
  154.         sum := 0;
  155.         bounds := theSprite^.hotRect;
  156.         OffsetRect(bounds, theSprite^.position.h, theSprite^.position.v);
  157.         p1 := bounds.topLeft;
  158.         p2.h := bounds.left;
  159.         p2.v := bounds.bottom;
  160.         p3.h := bounds.right;
  161.         p3.v := bounds.top;
  162.         p4 := bounds.botRight;
  163.  
  164.         if PtInGrid(p1) then
  165.             sum := sum + 1;
  166.         if PtInGrid(p2) then
  167.             sum := sum + 2;
  168.         if PtInGrid(p3) then
  169.             sum := sum + 4;
  170.         if PtInGrid(p4) then
  171.             sum := sum + 8;
  172.  
  173.         case sum of
  174.             0, 15: 
  175.                 Exit(GridTest);
  176. { Single corner}
  177.             1: 
  178.                 begin
  179.                     GetGridRect(p1, gridRect);
  180.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  181.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  182.                     else
  183.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  184.                 end;
  185.             2: 
  186.                 begin
  187.                     GetGridRect(p2, gridRect);
  188.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  189.                         theSprite^.speed.h := abs(theSprite^.speed.h)
  190.                     else
  191.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  192.                 end;
  193.             4: 
  194.                 begin
  195.                     GetGridRect(p3, gridRect);
  196.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  197.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  198.                     else
  199.                         theSprite^.speed.v := abs(theSprite^.speed.v);
  200.                 end;
  201.             8: 
  202.                 begin
  203.                     GetGridRect(p4, gridRect);
  204.                     if RectSeparateRect(SpritePtr(theSprite), gridRect) >= 2 then
  205.                         theSprite^.speed.h := -abs(theSprite^.speed.h)
  206.                     else
  207.                         theSprite^.speed.v := -abs(theSprite^.speed.v);
  208.                 end;
  209. { Sides}
  210.             3: {left}
  211.                 begin
  212.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  213.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  214.                 end;
  215.             5: { top}
  216.                 begin
  217.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  218.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  219.                 end;
  220.             10: { bottom}
  221.                 begin
  222.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  223.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  224.                 end;
  225.             12: { right}
  226.                 begin
  227.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  228.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  229.                 end;
  230.  
  231. { three corners}
  232.             7: {bottom right free}
  233.                 begin
  234.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  235.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  236.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  237.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  238.                 end;
  239.             11: { top right free}
  240.                 begin
  241.                     theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  242.                     theSprite^.speed.h := abs(theSprite^.speed.h);
  243.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  244.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  245.                 end;
  246.             13: { bottom left free}
  247.                 begin
  248.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  249.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  250.                     theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  251.                     theSprite^.speed.v := abs(theSprite^.speed.v);
  252.                 end;
  253.             14: { top left free}
  254.                 begin
  255.                     theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  256.                     theSprite^.speed.h := -abs(theSprite^.speed.h);
  257.                     theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  258.                     theSprite^.speed.v := -abs(theSprite^.speed.v);
  259.                 end;
  260.             6: { diagonal}
  261. {Diagonals are revised! Previously, the choice between the two positions was judged from speed.}
  262. {Now it picks the closest one.}
  263.                 begin
  264.                     case1.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  265.                     case1.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  266.                     case2.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  267.                     case2.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  268.                     diff1 := Abs(case1.h - theSprite^.position.h) + Abs(case1.v - theSprite^.position.v);
  269.                     diff2 := Abs(case2.h - theSprite^.position.h) + Abs(case2.v - theSprite^.position.v);
  270.  
  271. {if theSprite^.speed.h + theSprite^.speed.v > 0 then { if down-right speed}
  272.                     if diff1 < diff2 then
  273.                         begin
  274.                             theSprite^.position := case1;
  275. {theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;}
  276.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  277. {theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;}
  278.                             theSprite^.speed.v := -abs(theSprite^.speed.v);
  279.                         end
  280.                     else { else up-left speed}
  281.                         begin
  282.                             theSprite^.position := case2;
  283. {theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  284.                             theSprite^.speed.h := abs(theSprite^.speed.h);
  285. {theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  286.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  287.                         end;
  288.                 end;
  289.             9: { diagonal}
  290.                 begin
  291.                     case1.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;
  292.                     case1.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  293.                     case2.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  294.                     case2.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;
  295.                     diff1 := Abs(case1.h - theSprite^.position.h) + Abs(case1.v - theSprite^.position.v);
  296.                     diff2 := Abs(case2.h - theSprite^.position.h) + Abs(case2.v - theSprite^.position.v);
  297.  
  298. {if theSprite^.speed.h - theSprite^.speed.v > 0 then { if up-right speed}
  299.                     if diff1 < diff2 then
  300.                         begin
  301.                             theSprite^.position := case1;
  302. {theSprite^.position.h := (p4.h div kTileSizeH + 0) * kTileSizeH - theSprite^.hotRect.right;}
  303.                             theSprite^.speed.h := -abs(theSprite^.speed.h);
  304. {theSprite^.position.v := (p1.v div kTileSizeV + 1) * kTileSizeV - theSprite^.hotRect.top; {Corrected 23/1}
  305.                             theSprite^.speed.v := abs(theSprite^.speed.v);
  306.                         end
  307.                     else { else down-left speed}
  308.                         begin
  309.                             theSprite^.position := case2;
  310. {theSprite^.position.h := (p1.h div kTileSizeH + 1) * kTileSizeH - theSprite^.hotRect.left; {Corrected 23/1}
  311.                             theSprite^.speed.h := abs(theSprite^.speed.h);
  312. {theSprite^.position.v := (p4.v div kTileSizeV + 0) * kTileSizeV - theSprite^.hotRect.bottom;}
  313.                             theSprite^.speed.v := -abs(theSprite^.speed.v);
  314.                         end;
  315.                 end;
  316.         end; {case}
  317. {theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);}
  318. {theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);}
  319. {Change 23/1-97: Keep the "decimals!" This allows sprites that don't bounce to slide against walls.}
  320.         theSprite^.fixedPointPosition.h := BitOr(BSL(theSprite^.position.h, 4), BitAnd(theSprite^.fixedPointPosition.h, 15));
  321.         theSprite^.fixedPointPosition.v := BitOr(BSL(theSprite^.position.v, 4), BitAnd(theSprite^.fixedPointPosition.v, 15));
  322.     end; (*GridTest*)
  323.  
  324.     var
  325.         firstFace, secondFace, thirdFace: GrafPtr;
  326.  
  327.     procedure MoveSpriteInGrid (theSprite: FixSpritePtr);
  328. {    theSprite->speed.v++; // Simple gravity}
  329.     begin
  330.         theSprite^.fixedPointPosition.h := theSprite^.fixedPointPosition.h + theSprite^.speed.h;
  331.         theSprite^.fixedPointPosition.v := theSprite^.fixedPointPosition.v + theSprite^.speed.v;
  332.         theSprite^.position.h := BSR(theSprite^.fixedPointPosition.h, 4);
  333.         theSprite^.position.v := BSR(theSprite^.fixedPointPosition.v, 4);
  334.         GridTest(theSprite);
  335.         if KeepOnScreenFixed(theSprite) then
  336.             ;
  337.     end; (*MoveSpriteInGrid*)
  338.  
  339.  
  340. {Standard rect-based bounce-off collision handling.}
  341. {VAD ÄR DETTA FÖR SKIT???}
  342. {This routine seems to have been left here by mistake. I'll nuke it when I feel 100% sure.}
  343.     procedure HitSprite (theSprite: FixSpritePtr; anotherSprite: FixSpritePtr);
  344.         var
  345.             tempSpeed: Integer;
  346.     begin
  347.         if RectSeparate(SpritePtr(theSprite), SpritePtr(anotherSprite), kPushBoth) >= 2 then { 2 or 3: horizontal, otherwise vertical}
  348.             begin
  349.                 tempSpeed := theSprite^.speed.h;
  350.                 theSprite^.speed.h := anotherSprite^.speed.h;
  351.                 anotherSprite^.speed.h := tempSpeed;
  352.                 theSprite^.fixedPointPosition.h := BSL(theSprite^.position.h, 4);
  353.             end
  354.         else
  355.             begin
  356.                 tempSpeed := theSprite^.speed.v;
  357.                 theSprite^.speed.v := anotherSprite^.speed.v;
  358.                 anotherSprite^.speed.v := tempSpeed;
  359.                 theSprite^.fixedPointPosition.v := BSL(theSprite^.position.v, 4);
  360.             end;
  361.     end; (*HitSprite*)
  362.  
  363.  
  364.     procedure DrawAllTiles;
  365.         var
  366.             h, v: Integer;
  367.     begin
  368.         for h := 0 to kArraySizeH - 1 do
  369.             for v := 0 to kArraySizeV - 1 do
  370.                 DrawTile(h, v);
  371.     end; {DrawAllTiles}
  372.  
  373. end.